# 面向对象的三大特性
# 封装,把共性(属性，函数)搞在一起变成一个类
# 继承，子类继承父类的属性
# 多态：同一个名字的函数，拥有不同的效果

# 类的属性 vs 对象的属性
# 类的属性属于类，并且所有该类的对象都共享这个属性
# 对象的属性属于对象，self.xxx
class Animal:
    # 类的属性
    burudongwu = True

    # def __init__(self):
    #     print('Animal __init__')
    def __init__(self, name):
        self.__name = name
        print(self.__name, id(self.__name))

    def eat(self):
        print('Animal的吃')

    def __eat2(self):
        print('Animal的吃2')

    def sound(self):
        pass

    # 该函数为对象函数，如果要变成类的函数，需要加一个装饰器，加装饰器也就是给函数加点作料，加注解@classmethod
    @classmethod
    def piss(self):
        print('尿尿')


an1 = Animal('旺财2')
an2 = Animal('加菲猫2')
print(an1.burudongwu)
Animal.burudongwu = False
print(an2.burudongwu)
Animal.piss()


class Dog(Animal):
    def __init__(self):
        super().__init__('旺财')
        print('Dog __init__')

    def sound(self):
        print('汪汪汪')


class Cat(Animal):
    def __init__(self):
        super().__init__('加菲')
        print('Cat __init__')

    def sound(self):
        print('喵喵喵')


# 会先调用父类的init函数，再调用子类的初始化函数
dog = Dog()
dog.eat()
dog.sound()
# 父类的属性或者函数不放开对子类的继承可以在函数或者属性名称前面加上两个下划线，下面调用会报错
# 可以放开下面的两行代码调试下
# print(dog.__name)
# dog.__eat2()

cat = Cat()
cat.sound()


def makesounr(animal: Animal):
    animal.sound()


makesounr(dog)
makesounr(cat)
